package io.github.echarts.model.coordinate.cartesian;

import io.github.echarts.model.coordinate.CoordinateSystem;
import io.github.echarts.model.coordinate.CoordinateSystemType;
import io.github.echarts.model.coordinate.DataRange;
import io.github.echarts.model.coordinate.axis.AxisModel;
import io.github.echarts.model.geometry.Dimension;
import io.github.echarts.model.geometry.Rectangle;
import io.github.echarts.option.component.Axis;
import io.github.echarts.option.component.Grid;
import io.github.echarts.option.component.axis.AxisLine;
import io.github.echarts.option.component.axis.AxisTick;
import io.github.echarts.option.component.axis.AxisLabel;

/**
 * 笛卡尔坐标系的默认实现
 * 支持类别轴和数值轴
 */
public class DefaultCartesianCoordinateSystem implements CartesianCoordinateSystem {
    
    /**
     * 坐标系ID
     */
    private String id;
    
    /**
     * 网格配置
     */
    private Grid grid;
    
    /**
     * X轴配置
     */
    private Axis xAxis;
    
    /**
     * Y轴配置
     */
    private Axis yAxis;
    
    /**
     * X轴模型
     */
    private AxisModel xAxisModel;
    
    /**
     * Y轴模型
     */
    private AxisModel yAxisModel;
    
    /**
     * 数据范围
     */
    private DataRange dataRange;
    
    /**
     * 坐标转换器
     */
    private CartesianCoordinateTransformer transformer;
    
    /**
     * 坐标系尺寸
     */
    private Dimension dimension;
    
    /**
     * 坐标系区域
     */
    private Rectangle area;
    
    /**
     * 创建默认笛卡尔坐标系
     * 
     * @param id 坐标系ID
     * @param grid 网格配置
     * @param xAxis X轴配置
     * @param yAxis Y轴配置
     */
    public DefaultCartesianCoordinateSystem(String id, Grid grid, Axis xAxis, Axis yAxis) {
        this.id = id;
        this.grid = grid;
        this.xAxis = xAxis;
        this.yAxis = yAxis;
        this.dataRange = new DataRange(0, 100); // 默认数据范围，后续会更新
        
        // 创建轴模型
        if (xAxis != null) {
            this.xAxisModel = new AxisModel(xAxis);
        }
        if (yAxis != null) {
            this.yAxisModel = new AxisModel(yAxis);
        }
    }
    
    /**
     * 使用布局区域创建默认笛卡尔坐标系
     * 
     * @param id 坐标系ID
     * @param area 布局区域
     */
    public DefaultCartesianCoordinateSystem(String id, Rectangle area) {
        this.id = id;
        this.area = area;
        this.dimension = new Dimension(area.getWidth(), area.getHeight());
        this.dataRange = new DataRange(0, 100); // 默认数据范围，后续会更新
        this.transformer = new CartesianCoordinateTransformer(area);
    }
    
    /**
     * 使用布局区域创建默认笛卡尔坐标系（向后兼容）
     * 
     * @param area 布局区域
     * @deprecated 请使用带ID参数的构造函数
     */
    @Deprecated
    public DefaultCartesianCoordinateSystem(Rectangle area) {
        this("cartesian_" + System.currentTimeMillis(), area);
    }
    
    @Override
    public String getId() {
        return id;
    }
    
    @Override
    public CoordinateSystemType getType() {
        return CoordinateSystemType.CARTESIAN;
    }
    
    @Override
    public Dimension getDimension() {
        return dimension;
    }
    
    @Override
    public void initialize() {
        // 如果尺寸信息已设置，则初始化坐标转换器
        if (area != null) {
            this.dimension = new Dimension(area.getWidth(), area.getHeight());
            
            // 创建或更新坐标转换器
            if (this.transformer == null) {
                this.transformer = new CartesianCoordinateTransformer(area);
            } else {
                this.transformer.setArea(area);
            }
            
            // 确保轴模型被创建
            if (this.xAxisModel == null && xAxis != null) {
                this.xAxisModel = new AxisModel(xAxis);
            }
            
            if (this.yAxisModel == null && yAxis != null) {
                this.yAxisModel = new AxisModel(yAxis);
            }
            
            // 如果没有轴配置但需要轴模型，创建默认的
            if (this.xAxisModel == null) {
                // 创建默认X轴配置
                Axis defaultXAxis = new Axis();
                defaultXAxis.setType("category"); // 默认为类别轴
                defaultXAxis.setShow(true);
                
                // 创建默认轴线样式
                AxisLine axisLine = new AxisLine();
                axisLine.setShow(true);
                defaultXAxis.setAxisLine(axisLine);
                
                // 创建默认刻度样式
                AxisTick axisTick = new AxisTick();
                axisTick.setShow(true);
                defaultXAxis.setAxisTick(axisTick);
                
                // 创建默认标签样式
                AxisLabel axisLabel = new AxisLabel();
                axisLabel.setShow(true);
                defaultXAxis.setAxisLabel(axisLabel);
                
                // 设置默认类别数据
                defaultXAxis.setData(new String[]{"类别1", "类别2", "类别3", "类别4", "类别5"});
                
                this.xAxis = defaultXAxis;
                this.xAxisModel = new AxisModel(defaultXAxis);
            }
            
            if (this.yAxisModel == null) {
                // 创建默认Y轴配置
                Axis defaultYAxis = new Axis();
                defaultYAxis.setType("value"); // 默认为数值轴
                defaultYAxis.setShow(true);
                
                // 创建默认轴线样式
                AxisLine axisLine = new AxisLine();
                axisLine.setShow(true);
                defaultYAxis.setAxisLine(axisLine);
                
                // 创建默认刻度样式
                AxisTick axisTick = new AxisTick();
                axisTick.setShow(true);
                defaultYAxis.setAxisTick(axisTick);
                
                // 创建默认标签样式
                AxisLabel axisLabel = new AxisLabel();
                axisLabel.setShow(true);
                defaultYAxis.setAxisLabel(axisLabel);
                
                this.yAxis = defaultYAxis;
                this.yAxisModel = new AxisModel(defaultYAxis);
            }
            
            // 更新轴数据范围
            if (this.dataRange != null) {
                if (yAxisModel != null) {
                    yAxisModel.updateDataRange(dataRange);
                }
                
                if (xAxisModel != null && xAxis != null && "value".equals(xAxis.getType())) {
                    xAxisModel.updateDataRange(dataRange);
                }
            }
            
            // 确保轴的视觉元素可见
            ensureAxisVisualElementsVisible();
        }
    }
    
    /**
     * 确保坐标轴的视觉元素（轴线、刻度、标签）可见
     */
    private void ensureAxisVisualElementsVisible() {
        // 确保X轴视觉元素可见
        if (xAxis != null) {
            if (xAxis.getAxisLine() == null) {
                AxisLine axisLine = new AxisLine();
                axisLine.setShow(true);
                xAxis.setAxisLine(axisLine);
            }
            
            if (xAxis.getAxisTick() == null) {
                AxisTick axisTick = new AxisTick();
                axisTick.setShow(true);
                xAxis.setAxisTick(axisTick);
            }
            
            if (xAxis.getAxisLabel() == null) {
                AxisLabel axisLabel = new AxisLabel();
                axisLabel.setShow(true);
                xAxis.setAxisLabel(axisLabel);
            }
        }
        
        // 确保Y轴视觉元素可见
        if (yAxis != null) {
            if (yAxis.getAxisLine() == null) {
                AxisLine axisLine = new AxisLine();
                axisLine.setShow(true);
                yAxis.setAxisLine(axisLine);
            }
            
            if (yAxis.getAxisTick() == null) {
                AxisTick axisTick = new AxisTick();
                axisTick.setShow(true);
                yAxis.setAxisTick(axisTick);
            }
            
            if (yAxis.getAxisLabel() == null) {
                AxisLabel axisLabel = new AxisLabel();
                axisLabel.setShow(true);
                yAxis.setAxisLabel(axisLabel);
            }
        }
    }
    
    @Override
    public Rectangle getLayoutArea() {
        return area;
    }
    
    @Override
    public void setLayoutArea(Rectangle area) {
        this.area = area;
        this.dimension = new Dimension(area.getWidth(), area.getHeight());
        if (this.transformer == null) {
            this.transformer = new CartesianCoordinateTransformer(area);
        } else {
            this.transformer.setArea(area);
        }
    }
    
    @Override
    public double dataToCoord(double value, int axisIndex) {
        if (transformer == null) {
            return 0;
        }
        
        // axisIndex=0表示X轴，axisIndex=1表示Y轴
        if (axisIndex == 0) {
            // X轴数据转换
            DataRange xRange = xAxisModel != null ? xAxisModel.getDataRange() : dataRange;
            double ratio = xRange.normalize(value);
            return transformer.transformX(ratio);
        } else {
            // Y轴数据转换
            DataRange yRange = yAxisModel != null ? yAxisModel.getDataRange() : dataRange;
            double ratio = yRange.normalize(value);
            return transformer.transformY(ratio);
        }
    }
    
    @Override
    public double coordToData(double coord, int axisIndex) {
        if (transformer == null) {
            return 0;
        }
        
        // axisIndex=0表示X轴，axisIndex=1表示Y轴
        if (axisIndex == 0) {
            // X轴坐标转换
            double ratio = transformer.inverseTransformX(coord);
            DataRange xRange = xAxisModel != null ? xAxisModel.getDataRange() : dataRange;
            return xRange.denormalize(ratio);
        } else {
            // Y轴坐标转换
            double ratio = transformer.inverseTransformY(coord);
            DataRange yRange = yAxisModel != null ? yAxisModel.getDataRange() : dataRange;
            return yRange.denormalize(ratio);
        }
    }
    
    /**
     * 获取类别X位置
     * 
     * @param category 类别值
     * @return X坐标
     */
    public double getCategoryPositionX(Object category) {
        if (xAxisModel == null || !xAxisModel.isCategoryAxis()) {
            return 0;
        }
        
        int index = xAxisModel.getCategoryIndex(category);
        return getCategoryPositionXByIndex(index);
    }
    
    /**
     * 根据索引获取类别X位置
     * 
     * @param index 类别索引
     * @return X坐标
     */
    public double getCategoryPositionXByIndex(int index) {
        if (xAxisModel == null || !xAxisModel.isCategoryAxis() || index < 0) {
            return 0;
        }
        
        double totalCategories = xAxisModel.getCategoryCount();
        if (totalCategories == 0) {
            return 0;
        }
        
        // 计算类别中心位置的相对X坐标（0-1之间）
        double relativePosition = (index + 0.5) / totalCategories;
        
        // 转换为实际坐标
        return transformer.transformX(relativePosition);
    }
    
    /**
     * 获取类别宽度
     * 
     * @param category 类别值
     * @return 宽度
     */
    public double getCategoryWidth(Object category) {
        if (xAxisModel == null || !xAxisModel.isCategoryAxis()) {
            return 0;
        }
        
        int categoryCount = xAxisModel.getCategoryCount();
        if (categoryCount == 0) {
            return 0;
        }
        
        // 计算每个类别可用的宽度
        double unitWidth = area.getWidth() / categoryCount;
        
        // 留出一些间距，使柱状图等不会紧挨着
        return unitWidth * 0.6;
    }
    
    /**
     * 获取Y值的位置
     * 
     * @param value 数值
     * @return Y坐标
     */
    public double getValuePositionY(Number value) {
        if (value == null || yAxisModel == null) {
            return area.getY(); // 默认返回底部
        }
        
        DataRange range = yAxisModel.getDataRange();
        double min = range.getMin();
        double max = range.getMax();
        
        // 处理min=max的情况
        if (min == max) {
            return area.getY() + area.getHeight() / 2; // 居中
        }
        
        // 计算值在数据范围内的相对位置（0-1）
        double ratio = (value.doubleValue() - min) / (max - min);
        
        // 转换为Y坐标（注意：坐标系原点在左下角，Y轴向上为正）
        return transformer.transformY(ratio);
    }
    
    /**
     * 获取数据范围
     * 
     * @return 数据范围
     */
    @Override
    public DataRange getDataRange() {
        return dataRange;
    }
    
    /**
     * 设置数据范围
     * 
     * @param dataRange 数据范围
     */
    public void setDataRange(DataRange dataRange) {
        this.dataRange = dataRange;
        
        // 更新Y轴模型的数据范围
        if (yAxisModel != null) {
            yAxisModel.updateDataRange(dataRange);
        }
        
        // 仅当X轴是数值轴时更新其数据范围
        if (xAxisModel != null && xAxis != null && "value".equals(xAxis.getType())) {
            xAxisModel.updateDataRange(dataRange);
        }
    }
    
    /**
     * 更新坐标系的数据范围
     * 
     * @param min 最小值
     * @param max 最大值
     */
    public void updateDataRange(double min, double max) {
        // 确保有合理的数据范围（避免min=max的情况）
        if (Math.abs(max - min) < 0.000001) {
            // 如果数据范围太小，扩展一点
            double delta = Math.abs(min * 0.1);
            if (delta < 0.00001) delta = 1.0; // 避免值太小
            
            min = min - delta;
            max = max + delta;
        }
        
        // 如果是正数据，从0开始显示
        if (min > 0) {
            min = 0;
        }
        
        // 创建新的数据范围并设置
        DataRange newRange = new DataRange(min, max);
        setDataRange(newRange);
    }
    
    /**
     * 应用数据范围到坐标系
     * 
     * @param range 数据范围
     */
    @Override
    public void applyDataRange(DataRange range) {
        if (range == null) {
            return;
        }
        
        // 获取原始数据范围
        double min = range.getMin();
        double max = range.getMax();
        
        // 如果数据都是正数，从0开始显示
        if (min > 0) {
            min = 0;
        }
        
        // 如果数据范围太小，扩展一点
        if (Math.abs(max - min) < 0.000001) {
            max = min + 10; // 确保有一个合理的范围
        }
        
        // 创建调整后的数据范围
        DataRange adjustedRange = new DataRange(min, max);
        
        // 设置到坐标系
        setDataRange(adjustedRange);
    }
    
    /**
     * 获取X轴配置
     * 
     * @return X轴配置
     */
    public Axis getXAxis() {
        return xAxis;
    }
    
    /**
     * 获取Y轴配置
     * 
     * @return Y轴配置
     */
    public Axis getYAxis() {
        return yAxis;
    }
    
    /**
     * 获取X轴模型
     * 
     * @return X轴模型
     */
    @Override
    public AxisModel getXAxisModel() {
        return xAxisModel;
    }
    
    /**
     * 获取Y轴模型
     * 
     * @return Y轴模型
     */
    @Override
    public AxisModel getYAxisModel() {
        return yAxisModel;
    }
    
    /**
     * 获取坐标转换器
     * 
     * @return 坐标转换器
     */
    @Override
    public CartesianCoordinateTransformer getTransformer() {
        return transformer;
    }
    
    /**
     * 设置X轴配置
     * 
     * @param xAxis X轴配置
     */
    public void setXAxis(Axis xAxis) {
        this.xAxis = xAxis;
        
        // 更新轴模型
        if (xAxis != null) {
            this.xAxisModel = new AxisModel(xAxis);
        }
    }
    
    /**
     * 设置Y轴配置
     * 
     * @param yAxis Y轴配置
     */
    public void setYAxis(Axis yAxis) {
        this.yAxis = yAxis;
        
        // 更新轴模型
        if (yAxis != null) {
            this.yAxisModel = new AxisModel(yAxis);
        }
    }
    
    /**
     * 设置X轴模型
     * 
     * @param xAxisModel X轴模型
     */
    public void setXAxisModel(AxisModel xAxisModel) {
        this.xAxisModel = xAxisModel;
    }
    
    /**
     * 设置Y轴模型
     * 
     * @param yAxisModel Y轴模型
     */
    public void setYAxisModel(AxisModel yAxisModel) {
        this.yAxisModel = yAxisModel;
    }
} 